﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace Gestion.Common.Extensions
{
    public static class StringExtension
    {
        /// <summary>return string value or null if string is empty</summary>
        /// <param name="val">The value.</param>
        [DebuggerHidden]
        public static string IgnoreNull(this string val)
        {
            return (val ?? string.Empty);
        }

        public static T SafeParse<T>(this object val, T replaceTo) where T : struct
        {
            var value = (T?)SafeParse(val, typeof(T));
            if (!value.HasValue)
                return replaceTo;
            return value.Value;
        }

        /// <summary>attempts to parse string into specified primitive type and will return null if parsing 
        /// fails for any reason</summary>
        /// <param name="val">  The value to parse.</param>
        [DebuggerStepThrough]
        public static T? SafeParse<T>(this object val) where T : struct
        {
            return (T?)SafeParse(val, typeof(T));
        }

        /// <summary>attempts to parse string into specified primitive type and will return null if parsing 
        /// fails for any reason</summary>
        /// <param name="val">  The value to parse.</param>
        /// <param name="type">type to parse into</param>
        /// <exception cref="ArgumentException"><c>ArgumentException</c>.</exception>
        public static object SafeParse(this object val, Type type)
        {
            if (val is bool && type != typeof(bool))
                val = ((bool)val
                    ? 1
                    : 0);
            return type == null || val == null
                ? null
                : (!type.IsInstanceOfType(val))
                    ? SafeParse(val.ToString(), type)
                    : (type == typeof(double) && Double.IsNaN((double)val)
                        ? null
                        : val);
        }

        /// <summary>attempts to parse string into specified primitive type and will return null if parsing 
        /// fails for any reason</summary>
        /// <param name="val">  The value to parse.</param>
        /// <param name="type">type to parse into</param>
        /// <exception cref="ArgumentException"><c>ArgumentException</c>.</exception>
        public static object SafeParse(this string val, Type type)
        {
            type = (type != null && type.IsGenericType
                ? (Nullable.GetUnderlyingType(type) ?? type)
                : type);
            if (type == null)
                return null;
            if (type == typeof(string))
                return val;
            val = (val ?? String.Empty).Trim().Replace(",", "");
            if (val == String.Empty)
                return null;

            if (type == typeof(int))
            {
                int r;
                return (Int32.TryParse(val, out r)
                    ? r
                    : (int?)null);
            }
            if (type == typeof(long))
            {
                long r;
                return (Int64.TryParse(val, out r)
                    ? r
                    : (long?)null);
            }
            if (type == typeof(bool))
            {
                sbyte r;
                if (SByte.TryParse(val, out r))
                    return r;
                int idx = "0nNfF1yYtT".IndexOf(val[0]);
                return (idx < 0
                    ? (bool?)null
                    : (idx > 4));
            }
            if (type.IsEnum)
                try
                {
                    return Enum.Parse(type, val, true);
                }
                catch
                {
                    return null;
                }
            if (type == typeof(short))
            {
                short r;
                return (Int16.TryParse(val, out r)
                    ? r
                    : (short?)null);
            }
            if (type == typeof(double))
            {
                double r;
                return (Double.TryParse(val, out r)
                    ? (Double.IsNaN(r)
                        ? (double?)null
                        : r)
                    : null);
            }
            if (type == typeof(float))
            {
                float r;
                return (Single.TryParse(val, out r)
                    ? r
                    : (float?)null);
            }
            if (type == typeof(decimal))
            {
                decimal r;
                return (Decimal.TryParse(val, out r)
                    ? r
                    : (decimal?)null);
            }
            if (type == typeof(DateTime))
            {
                DateTime r;
                return (DateTime.TryParse(val, out r)
                    ? r
                    : (DateTime?)null);
            }
            if (type == typeof(DateTimeOffset))
            {
                DateTimeOffset r;
                return (DateTimeOffset.TryParse(val, out r)
                    ? r
                    : (DateTimeOffset?)null);
            }
            if (type == typeof(TimeSpan))
            {
                TimeSpan r;
                return (TimeSpan.TryParse(val, out r)
                    ? r
                    : (TimeSpan?)null);
            }
            if (type == typeof(uint))
            {
                uint r;
                return (UInt32.TryParse(val, out r)
                    ? r
                    : (uint?)null);
            }
            if (type == typeof(ulong))
            {
                ulong r;
                return (UInt64.TryParse(val, out r)
                    ? r
                    : (ulong?)null);
            }
            if (type == typeof(ushort))
            {
                ushort r;
                return (UInt16.TryParse(val, out r)
                    ? r
                    : (ushort?)null);
            }
            if (type == typeof(byte))
            {
                byte r;
                return (Byte.TryParse(val, out r)
                    ? r
                    : (byte?)null);
            }
            if (type == typeof(sbyte))
            {
                sbyte r;
                return (SByte.TryParse(val, out r)
                    ? r
                    : (sbyte?)null);
            }
            if (type == typeof(Guid))
            {
                Guid r;
                return (Guid.TryParse(val, out r)
                    ? r
                    : (Guid?)null);
            }
            if (type == typeof(byte[]))
            {
                try
                {
                    return Convert.FromBase64String(val);
                }
                catch
                {
                    return null;
                }
            }
            throw new ArgumentException("can not parse type: " + type.Name);
        }
    }
}
